package com.mybatis.jpa.statement;

import com.mybatis.jpa.annotation.DataPermisson;
import com.mybatis.jpa.meta.MybatisColumnMeta;
import com.mybatis.jpa.meta.PersistentMeta;
import com.mybatis.jpa.type.MethodConstants;
import com.mybatis.jpa.type.OperateEnum;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Set;

/**
 * SQL解析工具类</br>
 *
 * @author svili
 * @data 2017年5月8日
 */
public class SqlAssistant {

    private SqlAssistant() {
    }

    /**
     * 解析method的where条件,仅支持单一字段条件,如果没有where语句,返回空字符串""
     **/
    public static String buildSingleCondition(Method method, PersistentMeta persistentMeta) {
        return buildSingleCondition(method, persistentMeta, null);
    }

    /**
     * 解析method的where条件,仅支持单一字段条件,如果没有where语句,返回空字符串""
     **/
    public static String buildSingleCondition(Method method, PersistentMeta persistentMeta, String alias) {
        String methodType = resolveMethodType(method.getName());
        String sourceAlias = alias;
        if (alias == null) {
            alias = "";
            sourceAlias = "";
        } else {
            alias = alias + ".";
        }
        if (method.getName().equals(methodType)) {
            return "";
        }
        // 清除methodName中的methodType 和 By :expression包含
        // 条件字段(FieldName)、操作符类型(Like)
        String expression = method.getName().substring(methodType.length() + 2);
        OperateEnum operate = resolveOperate(expression);
        // 首字母小写
        String fieldName = StringUtils.uncapitalize(expression.replace(operate.getAlias(), "")).replace("CatTable", "");
        MybatisColumnMeta columnMeta;
        if (fieldName.equals("id") || fieldName.equals("idJpa")) {
            columnMeta = persistentMeta.getPrimaryColumnMeta();
        } else {
            columnMeta = persistentMeta.getColumnMetaMap().get(fieldName);
        }
        String versionSql = "";
        if (persistentMeta.isVersion()) {
            String versionField = persistentMeta.getVersionColumnMeta().getProperty();
            versionSql = "<if test=\" " + alias + versionField + " !=null \">" +
                    " AND " + persistentMeta.getVersionColumnMeta().getColumnName() + "=" + resolveSqlParameter(persistentMeta.getVersionColumnMeta(), sourceAlias) +
                    "</if>";
        }
        if (operate.equals(OperateEnum.ISNULL) || operate.equals(OperateEnum.NOTNULL)) {
            return " WHERE " + columnMeta.getColumnName() + operate.getOperate();
        } else {
            return " WHERE " + columnMeta.getColumnName() + operate.getOperate() + resolveSqlParameter(columnMeta, sourceAlias) + versionSql;
        }
    }

    /**
     * 解析method的where条件,仅支持单一字段条件,如果没有where语句,返回空字符串""
     **/
    public static String buildSingleCondition(Method method, PersistentMeta persistentMeta, boolean isParam) {
        String methodType = resolveMethodType(method.getName());
        if (method.getName().equals(methodType)) {
            return "";
        }
        // 清除methodName中的methodType 和 By :expression包含
        // 条件字段(FieldName)、操作符类型(Like)
        String expression = method.getName().substring(methodType.length() + 2);
        OperateEnum operate = resolveOperate(expression);
        // 首字母小写
        String fieldName = StringUtils.uncapitalize(expression.replace(operate.getAlias(), "")).replace("CatTable", "");
        MybatisColumnMeta columnMeta;

        if (fieldName.equals("idJpa") || fieldName.equals("id")) {
            columnMeta = persistentMeta.getPrimaryColumnMeta();
        } else {
            columnMeta = persistentMeta.getColumnMetaMap().get(fieldName);
        }
        if (operate.equals(OperateEnum.ISNULL) || operate.equals(OperateEnum.NOTNULL)) {
            return " WHERE " + columnMeta.getColumnName() + operate.getOperate();
        } else {
            if (isParam && persistentMeta.isCatTable()) {
                return " WHERE " + columnMeta.getColumnName() + operate.getOperate() + " #{param}";
            }
            return " WHERE " + columnMeta.getColumnName() + operate.getOperate() + resolveSqlParameter(columnMeta);
        }
    }

    /**
     * 解析method的where条件,仅支持单一字段条件,如果没有where语句,返回空字符串""
     **/
    public static String buildSingleConditionforParam(Method method, PersistentMeta persistentMeta) {
        return buildSingleCondition(method, persistentMeta, true);
    }
    /**
     * 拼接where 后面的条件
     *
     * @param persistentMeta model的信息
     * @param whereAlias   别名
     * @param isAppendEndWhere 是否自动拼接最后的</where>
     * @return where 1=1 and xxx
     */
    public static String builderModelWhere(PersistentMeta persistentMeta, String whereAlias,boolean isAppendEndWhere){
        StringBuilder result = new StringBuilder(" <where>");
        Set<String> keySet = persistentMeta.getColumnMetaMap().keySet();
        String entity = whereAlias;
        MybatisColumnMeta temp = null;
        String javaFieldName = null;
        for (String key : keySet) {

            temp = persistentMeta.getColumnMetaMap().get(key);
            javaFieldName = entity + temp.getProperty();
            // 列名字 如果有表别名的话就是  表别名 .列名 比如 select xx from student stu where  "stu.name"
            String columnName = temp.getColumnName();
            if (temp.isBetween()) {
                String betweenMapKey = entity + "between." + temp.getProperty() + "Min";
                result.append(" <if test=\"");
                result.append(betweenMapKey + "  !='' and   ");
                result.append(betweenMapKey + " !=null \"> ");
                result.append(" AND " + columnName + " <![CDATA[>=]]> #{" + betweenMapKey + "} ");
                result.append(" </if> ");
                betweenMapKey = entity + "between." + temp.getProperty() + "Max";
                result.append(" <if test=\"");
                result.append(betweenMapKey + "  !='' and   ");
                result.append(betweenMapKey + " !=null \"> ");
                result.append(" AND " + columnName + " <![CDATA[<=]]> #{" + betweenMapKey + "} ");
                result.append(" </if> ");
            }
            if (temp.isIn()) {
                result.append(" <if test=\"");
                result.append(entity + "inFilter." + temp.getProperty() + "  !='' and   ");
                result.append(entity + "inFilter." + temp.getProperty() + " !=null \"> ");
                result.append(" AND " + columnName + " IN (${" + entity + "inFilter." + temp.getProperty() + "}) ");
                result.append(" </if> ");
            }
            if (temp.isPermissonDataField()) {
                DataPermisson dataPermisson = temp.getField().getAnnotation(DataPermisson.class);
                result.append(" <if test=\"");
                result.append(entity + "dataPermissin." + dataPermisson.value() + "  !='' and   ");
                result.append(entity + "dataPermissin." + dataPermisson.value() + " !=null \"> ");
                result.append(" AND " + columnName + " IN (${" + entity + "dataPermissin." + dataPermisson.value() + "}) ");
                result.append(" </if> ");
            }
            result.append(" <if test=\"");
            if (String.class == temp.getType()) {
                result.append(javaFieldName + "  !='' and   ");
            }
            result.append(javaFieldName + " !=null \"> ");
            if (temp.isLike()) {
                result.append(" AND " + columnName + " LIKE  concat('%',#{" + javaFieldName + "},'%')");
            } else if (temp.isLLike()) {
                result.append(" AND " + columnName + " LIKE  concat('%',#{" + javaFieldName + "})");
            } else if (temp.isRLike()) {
                result.append(" AND " + columnName + " LIKE  concat(#{" + javaFieldName + "},'%')");
            } else if (temp.isnEQ())// 标记为不等于的话
            {
                result.append(" AND " + columnName + " != #{" + javaFieldName + ",jdbcType=" + temp.getJdbcType()
                        + "} ");
            } else {
                result.append(" AND " + columnName + " = #{" + javaFieldName + ",jdbcType=" + temp.getJdbcType()
                        + "} ");
            }
            result.append(" </if> ");
        }
        if(isAppendEndWhere){
            result.append(" </where> ");
        }
        return result.toString();
    }

    /**
     * 拼接where 后面的条件
     *
     * @param persistentMeta model的信息
     * @param isPager        调用方是否需要分页
     * @return where 1=1 and xxx
     */
    public static String builderModelWhere(PersistentMeta persistentMeta, boolean isPager) {
        String whereAlias = isPager ? "entity." : "";
        return builderModelWhere(persistentMeta,  whereAlias,true);
    }


    /**
     * 识别{@link MethodConstants}中定义的methodType
     */
    public static String resolveMethodType(String methodName) {
        methodName = methodName.replace("CatTable", "");
        // 注意顺序 insert insertSelective,insert应放在后面判断
        if (methodName.startsWith(MethodConstants.INSERT_SELECTIVE)) {
            return MethodConstants.INSERT_SELECTIVE;
        }

        if (methodName.startsWith(MethodConstants.INSERT)) {
            return MethodConstants.INSERT;
        }

        if (methodName.startsWith(MethodConstants.BATCH_INSERT)) {
            return MethodConstants.BATCH_INSERT;
        }

        if (methodName.startsWith(MethodConstants.DELETE_BEAN)) {
            return MethodConstants.DELETE_BEAN;
        }

        if (methodName.startsWith(MethodConstants.DELETE)) {
            return MethodConstants.DELETE;
        }

        if (methodName.startsWith(MethodConstants.UPDATE_SELECTIVE)) {
            return MethodConstants.UPDATE_SELECTIVE;
        }

        if (methodName.startsWith(MethodConstants.UPDATE)) {
            return MethodConstants.UPDATE;
        }

        if (methodName.startsWith(MethodConstants.BATCH_UPDATE_INCLUDE_NULL)) {
            return MethodConstants.BATCH_UPDATE_INCLUDE_NULL;
        }

        if (methodName.startsWith(MethodConstants.BATCH_UPDATE)) {
            return MethodConstants.BATCH_UPDATE;
        }
        if (methodName.startsWith(MethodConstants.SELECT_PAGE_FOR_ORDER)) {
            return MethodConstants.SELECT_PAGE_FOR_ORDER;
        }
        if (methodName.startsWith(MethodConstants.SELECT_PAGE)) {
            return MethodConstants.SELECT_PAGE;
        }

        if (methodName.startsWith(MethodConstants.SELECT_COUNT_ADVANCE)) {
            return MethodConstants.SELECT_COUNT_ADVANCE;
        }
        if (methodName.startsWith(MethodConstants.SELECT_COUNT)) {
            return MethodConstants.SELECT_COUNT;
        }

        if (methodName.startsWith(MethodConstants.SELECT_BEAN)) {
            return MethodConstants.SELECT_BEAN;
        }
        if (methodName.startsWith(MethodConstants.SELECT_NESTED_FOR_ORDER)) {
            return MethodConstants.SELECT_NESTED_FOR_ORDER;
        }
        if (methodName.startsWith(MethodConstants.SELECT_NESTED)) {
            return MethodConstants.SELECT_NESTED;
        }

        if (methodName.startsWith(MethodConstants.SELECT)) {
            return MethodConstants.SELECT;
        }
        // throw e
        return null;
    }

    /**
     * 识别@{link OperateEnum}定义的条件操作符
     */
    private static OperateEnum resolveOperate(String expression) {
        OperateEnum[] enums = OperateEnum.values();
        for (OperateEnum operate : enums) {
            if (expression.endsWith(operate.getAlias())) {
                return operate;
            }
        }
        return OperateEnum.EQUAL;
    }

    /**
     * 装配sql中动态参数的占位符 #{paramterName,jdbcType=,typeHandler=}
     */
    public final static String resolveSqlParameter(MybatisColumnMeta columnMeta) {

        return resolveSqlParameter(columnMeta, "");
    }

    /**
     * 装配sql中动态参数的占位符 #{alias.paramterName,jdbcType=,typeHandler=}
     */
    public final static String resolveSqlParameter(MybatisColumnMeta columnMeta, String alias) {
        String sqlParameter = "#{";
        if (alias != null && !"".equals(alias)) {
            sqlParameter += alias + ".";
        }
        sqlParameter += columnMeta.getProperty();

        // jdbcType
        if (columnMeta.getJdbcTypeAlias() != null) {
            sqlParameter += ", jdbcType=" + columnMeta.getJdbcTypeAlias();
        }
        // typeHandler
        if (columnMeta.getTypeHandlerClass() != null) {
            sqlParameter += ", typeHandler=" + columnMeta.getTypeHandlerClass().getName();
        }
        sqlParameter += "} ";

        return sqlParameter;
    }

}
